"""
RedFire Gateway 适配器
===================

统一的数据源接入框架，支持多种金融数据源的标准化接入。
基于事件驱动架构，提供高性能、高可靠的实时数据处理能力。

特性：
- 统一的数据源接入接口
- 事件驱动的数据分发机制
- 自动重连和错误恢复
- 数据质量监控和验证
- 可插拔的数据源适配器
"""

from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Any, Callable, AsyncIterator
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
import asyncio
import logging
from contextlib import asynccontextmanager

# from backend.services.market_data_service.config.service_config import get_config


class DataSourceType(Enum):
    """数据源类型枚举"""
    CTP_FUTURES = "ctp_futures"          # CTP期货
    CTP_STOCKS = "ctp_stocks"            # CTP股票
    THS_DATA = "ths_data"                # 同花顺数据
    WIND_DATA = "wind_data"              # Wind数据
    BINANCE = "binance"                  # 币安
    HUOBI = "huobi"                      # 火币
    OKEX = "okex"                        # OKEx
    CUSTOM = "custom"                    # 自定义数据源


class ConnectionStatus(Enum):
    """连接状态枚举"""
    DISCONNECTED = "disconnected"        # 未连接
    CONNECTING = "connecting"            # 连接中
    CONNECTED = "connected"              # 已连接
    RECONNECTING = "reconnecting"        # 重连中
    ERROR = "error"                      # 错误状态


@dataclass
class MarketDataTick:
    """标准化的Tick数据结构"""
    symbol: str                          # 合约代码
    exchange: str                        # 交易所
    datetime: datetime                   # 时间戳
    
    # 价格信息
    last_price: float                    # 最新价
    open_price: float                    # 开盘价
    high_price: float                    # 最高价
    low_price: float                     # 最低价
    pre_close: float                     # 前收盘价
    
    # 成交信息
    volume: int                          # 成交量
    turnover: float                      # 成交额
    open_interest: int = 0               # 持仓量(期货)
    
    # 买卖盘信息
    bid_prices: List[float] = field(default_factory=list)      # 买价列表
    bid_volumes: List[int] = field(default_factory=list)       # 买量列表
    ask_prices: List[float] = field(default_factory=list)      # 卖价列表
    ask_volumes: List[int] = field(default_factory=list)       # 卖量列表
    
    # 扩展字段
    extra_data: Dict[str, Any] = field(default_factory=dict)   # 扩展数据
    
    # 数据源信息
    source: str = ""                     # 数据源标识
    gateway: str = ""                    # 网关标识


@dataclass
class MarketDataBar:
    """标准化的K线数据结构"""
    symbol: str                          # 合约代码
    exchange: str                        # 交易所
    datetime: datetime                   # 时间戳
    interval: str                        # 周期(1m, 5m, 1h, 1d等)
    
    # OHLCV数据
    open_price: float                    # 开盘价
    high_price: float                    # 最高价
    low_price: float                     # 最低价
    close_price: float                   # 收盘价
    volume: int                          # 成交量
    turnover: float                      # 成交额
    open_interest: int = 0               # 持仓量(期货)
    
    # 扩展字段
    extra_data: Dict[str, Any] = field(default_factory=dict)
    source: str = ""
    gateway: str = ""


@dataclass
class ContractInfo:
    """合约信息数据结构"""
    symbol: str                          # 合约代码
    exchange: str                        # 交易所
    name: str                            # 合约名称
    product: str                         # 品种
    size: int                            # 合约乘数
    pricetick: float                     # 最小变动价位
    min_volume: int = 1                  # 最小交易量
    stop_supported: bool = True          # 是否支持止损
    net_position: bool = True            # 是否净持仓
    history_data: bool = True            # 是否支持历史数据
    
    # 扩展字段
    extra_data: Dict[str, Any] = field(default_factory=dict)
    source: str = ""
    gateway: str = ""


class RedFireGatewayAdapter(ABC):
    """
    RedFire网关适配器基类
    
    定义了数据源适配器的标准接口，所有具体的数据源适配器都需要继承此类。
    提供了连接管理、数据订阅、错误处理等基础功能。
    """
    
    def __init__(self, 
                 gateway_name: str,
                 data_source_type: DataSourceType,
                 config: Dict[str, Any] = None):
        """
        初始化网关适配器
        
        Args:
            gateway_name: 网关名称
            data_source_type: 数据源类型
            config: 配置参数
        """
        self.gateway_name = gateway_name
        self.data_source_type = data_source_type
        self.config = config or {}
        
        # 状态管理
        self.status = ConnectionStatus.DISCONNECTED
        self.connected = False
        self._reconnect_count = 0
        self._max_reconnect = self.config.get("max_reconnect", 10)
        self._reconnect_interval = self.config.get("reconnect_interval", 5)
        
        # 订阅管理
        self._subscribed_symbols: Dict[str, Dict[str, Any]] = {}
        self._contracts: Dict[str, ContractInfo] = {}
        
        # 事件回调
        self._tick_callbacks: List[Callable] = []
        self._bar_callbacks: List[Callable] = []
        self._contract_callbacks: List[Callable] = []
        self._status_callbacks: List[Callable] = []
        
        # 日志记录器
        self.logger = logging.getLogger(f"redfire.gateway.{gateway_name}")
        
    @abstractmethod
    async def connect(self) -> bool:
        """
        连接到数据源
        
        Returns:
            bool: 连接是否成功
        """
        pass
    
    @abstractmethod
    async def disconnect(self) -> bool:
        """
        断开数据源连接
        
        Returns:
            bool: 断开是否成功
        """
        pass
    
    @abstractmethod
    async def subscribe_tick(self, symbol: str, exchange: str = "") -> bool:
        """
        订阅Tick数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            
        Returns:
            bool: 订阅是否成功
        """
        pass
    
    @abstractmethod
    async def subscribe_bar(self, symbol: str, exchange: str = "", interval: str = "1m") -> bool:
        """
        订阅K线数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            interval: K线周期
            
        Returns:
            bool: 订阅是否成功
        """
        pass
    
    @abstractmethod
    async def unsubscribe_tick(self, symbol: str, exchange: str = "") -> bool:
        """
        取消订阅Tick数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            
        Returns:
            bool: 取消订阅是否成功
        """
        pass
    
    @abstractmethod
    async def unsubscribe_bar(self, symbol: str, exchange: str = "", interval: str = "1m") -> bool:
        """
        取消订阅K线数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            interval: K线周期
            
        Returns:
            bool: 取消订阅是否成功
        """
        pass
    
    @abstractmethod
    async def query_contracts(self) -> List[ContractInfo]:
        """
        查询所有合约信息
        
        Returns:
            List[ContractInfo]: 合约信息列表
        """
        pass
    
    @abstractmethod
    async def query_history(self, 
                           symbol: str, 
                           exchange: str = "",
                           start: datetime = None,
                           end: datetime = None,
                           interval: str = "1m") -> List[MarketDataBar]:
        """
        查询历史数据
        
        Args:
            symbol: 合约代码
            exchange: 交易所代码
            start: 开始时间
            end: 结束时间
            interval: K线周期
            
        Returns:
            List[MarketDataBar]: 历史K线数据
        """
        pass
    
    # 回调函数管理
    def add_tick_callback(self, callback: Callable[[MarketDataTick], None]):
        """添加Tick数据回调函数"""
        if callback not in self._tick_callbacks:
            self._tick_callbacks.append(callback)
    
    def add_bar_callback(self, callback: Callable[[MarketDataBar], None]):
        """添加K线数据回调函数"""
        if callback not in self._bar_callbacks:
            self._bar_callbacks.append(callback)
    
    def add_contract_callback(self, callback: Callable[[ContractInfo], None]):
        """添加合约信息回调函数"""
        if callback not in self._contract_callbacks:
            self._contract_callbacks.append(callback)
    
    def add_status_callback(self, callback: Callable[[ConnectionStatus], None]):
        """添加状态变化回调函数"""
        if callback not in self._status_callbacks:
            self._status_callbacks.append(callback)
    
    # 事件触发方法
    async def _on_tick(self, tick: MarketDataTick):
        """处理Tick数据事件"""
        for callback in self._tick_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(tick)
                else:
                    callback(tick)
            except Exception as e:
                self.logger.error(f"Tick回调函数执行失败: {e}")
    
    async def _on_bar(self, bar: MarketDataBar):
        """处理K线数据事件"""
        for callback in self._bar_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(bar)
                else:
                    callback(bar)
            except Exception as e:
                self.logger.error(f"K线回调函数执行失败: {e}")
    
    async def _on_contract(self, contract: ContractInfo):
        """处理合约信息事件"""
        self._contracts[f"{contract.symbol}.{contract.exchange}"] = contract
        for callback in self._contract_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(contract)
                else:
                    callback(contract)
            except Exception as e:
                self.logger.error(f"合约信息回调函数执行失败: {e}")
    
    async def _on_status_change(self, status: ConnectionStatus):
        """处理状态变化事件"""
        old_status = self.status
        self.status = status
        self.connected = (status == ConnectionStatus.CONNECTED)
        
        self.logger.info(f"网关状态变化: {old_status.value} -> {status.value}")
        
        for callback in self._status_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(status)
                else:
                    callback(status)
            except Exception as e:
                self.logger.error(f"状态变化回调函数执行失败: {e}")
    
    # 自动重连机制
    async def _auto_reconnect(self):
        """自动重连机制"""
        while self._reconnect_count < self._max_reconnect:
            self.logger.info(f"尝试重连 ({self._reconnect_count + 1}/{self._max_reconnect})")
            await self._on_status_change(ConnectionStatus.RECONNECTING)
            
            if await self.connect():
                self.logger.info("重连成功")
                self._reconnect_count = 0
                return True
            
            self._reconnect_count += 1
            await asyncio.sleep(self._reconnect_interval)
        
        self.logger.error(f"重连失败，已达到最大重连次数: {self._max_reconnect}")
        await self._on_status_change(ConnectionStatus.ERROR)
        return False
    
    # 工具方法
    def get_contract(self, symbol: str, exchange: str = "") -> Optional[ContractInfo]:
        """获取合约信息"""
        key = f"{symbol}.{exchange}" if exchange else symbol
        return self._contracts.get(key)
    
    def get_subscribed_symbols(self) -> List[str]:
        """获取已订阅的合约列表"""
        return list(self._subscribed_symbols.keys())
    
    def is_connected(self) -> bool:
        """检查是否已连接"""
        return self.connected
    
    def get_status(self) -> ConnectionStatus:
        """获取当前状态"""
        return self.status
    
    # 上下文管理器支持
    @asynccontextmanager
    async def connection(self):
        """连接上下文管理器"""
        try:
            await self.connect()
            yield self
        finally:
            await self.disconnect()
    
    # 健康检查
    async def health_check(self) -> Dict[str, Any]:
        """健康检查"""
        return {
            "gateway_name": self.gateway_name,
            "data_source_type": self.data_source_type.value,
            "status": self.status.value,
            "connected": self.connected,
            "subscribed_symbols": len(self._subscribed_symbols),
            "contracts_loaded": len(self._contracts),
            "reconnect_count": self._reconnect_count
        }
    
    def __repr__(self) -> str:
        return f"<RedFireGatewayAdapter({self.gateway_name}, {self.data_source_type.value}, {self.status.value})>"